// #include <iostream>

// using namespace std;

// 标准库从C++17开始支持了any这个类，这个类很有用，它对外表现成一个单独的数据类型，内部可以用来表示任何类型值，
// 有时候我们想在基于C++11/14的项目中用any这个功能

// 如果使用一个容器来表示多种数据类型的话，首先想到的是使用模板：
// 下面的写法肯定是不行的
// template <class K>
// class Any
// {
// public:
//     Any() : _value(0) {}
//     Any(K value = 10) : _value(value) {}

//     Any &operator=(const K &value)
//     {
//         _value = value;
//         return *this;
//     }

//     K getvalue() { return _value; }

// private:
//     K _value;
// };

// int main(void)
// {
//     Any<int> a = 1;
//     cout << a.getvalue() << endl;

//     return 0;
// }

// ——————————————————————————————————————————————————————————————————————————————

// 下面的这种情况是有问题的，感觉把Any类模板化的作用是一样的：
// 这样就没法去类型化了，holder有了类型，就只能保存对应类型的数据了，
// 而any是可以保存任意类型的，因为保存的都是子类对象，用父类指针来访问，这样可以完成去类型化
// class Any
// {
// private:
//     template <class T>
//     class holder
//     {
//     private:
//         T _val;

//     public:
//         virtual ~holder() {}
//         const std::type_info &type(){
//             return typeid(T);
//         }
//         holder *clone(){
//             return new holder(_val);
//         }
//     };

//     holder *_content;
// }

// ————————————————————————————————————————————————————————————————————————————

#include <iostream>
#include <typeinfo>
#include <cassert>
#include <unistd.h>
#include <any>

class Any
{
private:
    // 父类
    class holder
    {
    public:
        virtual ~holder() {}
        virtual const std::type_info &type() = 0;
        virtual holder *clone() = 0;
    };

    // 子类
    template <class T>
    class placeholder : public holder
    {
    public:
        placeholder(const T &val) : _val(val) {}
        // 获取子类对象保存的数据类型
        virtual const std::type_info &type() { return typeid(T); }
        // 针对当前的对象自身，克隆出一个新的子类对象
        virtual holder *clone() { return new placeholder(_val); }

        // private:
    public:
        T _val;
    };

    holder *_content;

public:
    Any() : _content(nullptr) {}
    template <class T>
    Any(const T &val) : _content(new placeholder<T>(val)) {}
    Any(const Any &other) : _content(other._content ? other._content->clone() : nullptr) {}
    ~Any() { delete _content; }

    Any &swap(Any &other)
    {
        std::swap(_content, other._content);
        return *this;
    }

    // 返回子类对象保存的数据指针
    template <class T>
    T *get()
    {
        // 要想获取数据类型，必须知道保存的数据类型一致
        assert(typeid(T) == _content->type());
        return &((placeholder<T> *)_content)->_val;
    }

    // 赋值运算符的重载函数
    template <class T>
    Any &operator=(const T &val)
    {
        // 为val构造一个临时的通用容器，然后与当前容器自身进行指针交换，临时对象释放的时候，原先保存的数据也就释放了
        Any(val).swap(*this);
        return *this;
    }
    Any &operator=(const Any &other)
    {
        Any(other).swap(*this);
        return *this;
    }
};

class Test
{
public:
    Test() { std::cout << "构造" << std::endl; }
    Test(const Test &t) { std::cout << "拷贝" << std::endl; }
    ~Test() { std::cout << "析构" << std::endl; }
};

int main(void)
{
    // #include <any> 头文件在 C++17 中才有的: g++ any.cc -o any -g -std=c++17
    // std::any a;
    // a = 10;
    // int *pi = std::any_cast<int>(&a);
    // std::cout << *pi << std::endl;

    // a = std::string("hello world");
    // std::string *ps = std::any_cast<std::string>(&a);
    // std::cout << *ps << std::endl;

    Any a;
    {
        Test t;
        a = t;
    }
    a = 10;
    int *pa = a.get<int>();
    std::cout << *pa << std::endl;

    a = std::string("nihao");
    std::string *ps = a.get<std::string>();
    std::cout << *ps << std::endl;

    while (true)
        sleep(1);

    return 0;
}
